package com.yumeng.framework.auth.security.config;

import com.yumeng.common.exception.YumengException;
import com.yumeng.common.helper.AssertHelper;
import com.yumeng.framework.auth.config.BaseAuthConfiguration;
import com.yumeng.common.data.enums2.AuthFrame;
import com.yumeng.framework.auth.security.authentication.custom.CustomWebAuthenticationDetailsSource;
import com.yumeng.framework.auth.security.configurers.MyAbstractAuthenticationFilterConfigurer;
import com.yumeng.framework.auth.security.configurers.NormalLoginConfigurer;
import com.yumeng.framework.auth.security.configurers.SmsLoginConfigurer;
import com.yumeng.framework.auth.security.userdetails.NormalUserDetailsServiceImpl;
import com.yumeng.framework.auth.service.auth.NormalAuthService;
import com.yumeng.framework.auth.service.auth.SmsAuthService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.*;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
import org.springframework.security.web.csrf.CsrfTokenRequestAttributeHandler;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.security.web.util.matcher.OrRequestMatcher;

import java.util.Map;

import static com.yumeng.framework.auth.security.configurers.CaptchaVerifyConfigurer.captchaVerify;
import static com.yumeng.framework.auth.security.configurers.NormalLoginConfigurer.normalLogin;
import static com.yumeng.framework.auth.security.configurers.SmsLoginConfigurer.smsLogin;

/**
 * SpringSecurity配置文件
 *
 * @author wxd
 * @date 2024/6/13 上午10:01
 */
@Slf4j
public abstract class SecurityConfiguration extends BaseAuthConfiguration {

    @Override
    protected AuthFrame currAuthFrame() {
        return AuthFrame.SECURITY;
    }

    private NormalAuthService normalAuthService;
    private SmsAuthService smsAuthService;
    private AuthenticationConfiguration authenticationConfiguration;

    /**
     * 普通认证
     * @param normalAuthService
     */
    @Autowired
    public void setNormalAuthService(NormalAuthService normalAuthService) {
        this.normalAuthService = normalAuthService;
        log.info("当前NormalAuthService：{}", normalAuthService.getClass().getName());
    }

    /**
     * 手机短信认证（可选）
     * @param smsAuthService
     */
    @Autowired(required = false)
    private void setSmsAuthService(SmsAuthService smsAuthService){
        this.smsAuthService = smsAuthService;
        log.info("当前SmsAuthService：{}", smsAuthService.getClass().getName());
    }

    @Autowired
    public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
        this.authenticationConfiguration = authenticationConfiguration;
    }

    //region 认证与权限

    /**
     * 直接放行的URL
     */
    protected String[] getPermitAllUrls() {
        return null;
    }

    /**
     * 需要指定角色
     */
    protected Map<String, String> getHasRoleMap() {
        return null;
    }

    /**
     * 需要指定权限
     */
    protected Map<String, String> getHasAuthorityMap() {
        return null;
    }

    /**
     * 自定义认证入口点【未认证】
     */
    protected AuthenticationEntryPoint getAuthenticationEntryPoint(){
        return null;
    }

    /**
     * 拒绝访问处理器【权限不足】
     *
     * @return
     */
    protected AccessDeniedHandler getAccessDeniedHandler(){
        return null;
    }

    //endregion

    //region 登录配置

    /**
     * 是否启用自定义认证（手机短信）
     * @return
     */
    protected boolean enableSmsAuth(){
        return false;
    }

    /**
     * 是否启用自定义认证（普通）
     * @return
     */
    protected boolean enableNormalAuth(){
        return false;
    }

    /**
     * 使用默认登录页面
     *
     * @return
     */
    protected boolean useDefaultLoginUrl(){
        return false;
    }

    /**
     * 是否开启验证码
     * @return
     */
    protected boolean enableCaptcha(){
        return false;
    }

    /**
     * 客户端类型参数
     * @return
     */
    private String getClientTypeParameter(){
        return yumengAuthProperties.getBasic().getClientTypeParameter();
    }

    /**
     * 登录用户名参数
     */
    private String getLoginUsernameParameter() {
        return yumengAuthProperties.getBasic().getUsernameParameter();
    }

    /**
     * 登录密码参数
     */
    private String getLoginPasswordParameter() {
        return yumengAuthProperties.getBasic().getPasswordParameter();
    }

    /**
     * 登录用户名参数（手机验证码）
     */
    private String getSmsLoginUsernameParameter() {
        return yumengAuthProperties.getBasic().getSmsUsernameParameter();
    }

    /**
     * 登录密码参数（手机验证码）
     */
    private String getSmsLoginPasswordParameter() {
        return yumengAuthProperties.getBasic().getSmsPasswordParameter();
    }


    /**
     * 认证成功处理（会覆盖loginSuccessUrl）【认证成功】
     */
    protected AuthenticationSuccessHandler getAuthenticationSuccessHandler() {
        return null;
    }

    /**
     * 认证失败处理（会覆盖loginFailureUrl）【认证失败】
     */
    protected AuthenticationFailureHandler getAuthenticationFailureHandler() {
        return null;
    }

    //endregion

    //region 注销配置
    /**
     * 注销时需要删除的cookie
     */
    protected String[] getDeleteCookies() {
        return null;
    }
    /**
     * 自定义注销处理器
     */
    protected LogoutHandler getLogoutHandler() {
        //new CustomLogoutHandler()
        return null;
    }
    /**
     * 自定义注销成功处理器【注销登录】
     */
    protected LogoutSuccessHandler getLogoutSuccessHandler() {
        return null;
    }
    //endregion

    //region 会话配置
    /**
     * 会话超时（失效）策略 （会覆盖InvalidSessionUrl）
     */
    protected InvalidSessionStrategy getInvalidSessionStrategy() {
        return null;
    }

    /**
     * 会话到期策略（在线踢人）（会覆盖ExpiredSessionUrl）
     */
    protected SessionInformationExpiredStrategy getSessionInformationExpiredStrategy() {
        return null;
    }

    /**
     * 最大会话数
     */
    protected Integer getMaxSessions() {
        return null;
    }

    /**
     * 是否阻止其他登录
     */
    protected boolean maxSessionsPreventsLogin() {
        return false;
    }

    //endregion

    //region 记住我配置

    /**
     * 记住我模式
     */
    protected RememberMeModel getRememberMeModel() {
        return RememberMeModel.COOKIE_REP;
    }

    /**
     * 是否总是记住我
     */
    protected boolean getAlwaysRememberMe() {
        return false;
    }

    /**
     * 记住我是否使用安全Cookie（https）
     */
    protected boolean getRememberMeSecureCookie() {
        return false;
    }

    /**
     * 记住我cookie域名
     */
    protected String getRememberMeCookieDomain() {
        return null;
    }

    /**
     * 记住我参数
     */
    private String getRememberMeParameter() {
        return yumengAuthProperties.getBasic().getRememberMeParameter();
    }

    /**
     * 记住我cookie名称
     */
    protected String getRememberMeCookieName() {
        return "m-rbe-ck-key";
    }

    /**
     * 记住我有效时间（秒）
     */
    protected int getRememberMeValiditySeconds() {
        return 60 * 60 * 24 * 7;
    }

    /**
     * 记住我Key
     */
    protected String getRememberMeKey() {
        return "my-rmb-me-key-9527-869883641814097920";
    }

    /**
     * 获取持久化的token存储方式
     */
    protected PersistentTokenRepository getPersistentTokenRepository() {
        return null;
    }

    //endregion

    //region CSRF配置

    /**
     * Csrf模式
     */
    protected CsrfModel getCsrfModel() {
        return CsrfModel.COOKIE_REP;
    }

    /**
     * CsrfCookie名称
     *
     */
    private String getCsrfCookieName(){
        return yumengAuthProperties.getBasic().getCsrfCookieName();
    }
    //endregion

    //region OAuth2配置

    /***
     * 启用OAuth2
     * @return
     */
    protected boolean enableOAuth2(){
        return false;
    }

    //endregion

    //region 其他

    protected boolean enableRequestCache(){
        return true;
    }

    protected boolean enableAnonymous(){
        return true;
    }

    //endregion

    //region 内部默认配置

    /**
     * 注销时需要删除的cookie（默认）
     */
    protected String[] getDefaultDeleteCookies() {
        return new String[]{"JSESSIONID", getRememberMeCookieName(), getCsrfCookieName()};
    }

    //endregion

    @Bean
    public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
        AssertHelper.assertNotBlank(getLoginProcessingUrl(), "getLoginProcessingUrl()是空");
        AssertHelper.assertNotBlank(getLoginUsernameParameter(), "getLoginUsernameParameter()是空");
        AssertHelper.assertNotBlank(getLoginPasswordParameter(), "getLoginPasswordParameter()是空");
        AssertHelper.assertNotBlank(getLoginSuccessUrl(), "getLoginSuccessUrl()是空");
        AssertHelper.assertNotBlank(getLoginFailureUrl(), "getLoginFailureUrl()是空");
        AssertHelper.assertNotBlank(getLogoutProcessingUrl(), "getLogoutProcessingUrl()是空");
        AssertHelper.assertNotBlank(getLogoutSuccessUrl(), "getLogoutSuccessUrl()是空");
        AssertHelper.assertNotBlank(getInvalidSessionUrl(), "getInvalidSessionUrl()是空");
        AssertHelper.assertNotBlank(getExpiredSessionUrl(), "getExpiredSessionUrl()是空");
        AssertHelper.assertNotNull(getRememberMeModel(), "getRememberMeModel()是null");
        AssertHelper.assertNotBlank(getRememberMeParameter(), "getRememberMeParameter()是空");
        AssertHelper.assertNotBlank(getRememberMeCookieName(), "getRememberMeCookieName()是空");
        AssertHelper.assertNotBlank(getRememberMeKey(), "getRememberMeKey()是空");
        AssertHelper.assertNotNull(getCsrfModel(), "getCsrfModel()是null");
        AssertHelper.assertNotBlank(getCsrfCookieName(), "getCsrfCookieName()是空");

        if (useDefaultLoginUrl() && enableNormalAuth()){
            throw new YumengException("使用框架自带登录页面时，必须使用标准认证流程");
        }
        if (enableSmsAuth()){
            AssertHelper.assertNotBlank(getSmsLoginUsernameParameter(), "getSmsLoginUsernameParameter()是空");
            AssertHelper.assertNotBlank(getSmsLoginPasswordParameter(), "getSmsLoginPasswordParameter()是空");
            AssertHelper.assertNotNull(smsAuthService, "SmsAuthService接口未实现");
        }

        //预处理
        if (!useDefaultLoginUrl()){
            yumengAuthProperties.getBasic().setUseLoginUrl(true);
        }else{
            yumengAuthProperties.getBasic().setUseLoginUrl(false);
        }

        //认证与权限
        String[] permitAllUrls = getPermitAllUrls();
        Map<String, String> hasRoleMap = getHasRoleMap();
        Map<String, String> hasAuthorityMap = getHasAuthorityMap();
        String[] defaultPermitAllUrls = defaultPermitAllUrls();
        //异常配置
        AuthenticationEntryPoint authenticationEntryPoint = getAuthenticationEntryPoint();
        AccessDeniedHandler accessDeniedHandler = getAccessDeniedHandler();
        //表单登录
        AuthenticationSuccessHandler authenticationSuccessHandler = getAuthenticationSuccessHandler();
        AuthenticationFailureHandler authenticationFailureHandler = getAuthenticationFailureHandler();
        //注销
        LogoutHandler logoutHandler = getLogoutHandler();
        LogoutSuccessHandler logoutSuccessHandler = getLogoutSuccessHandler();
        //会话
        InvalidSessionStrategy invalidSessionStrategy = getInvalidSessionStrategy();
        SessionInformationExpiredStrategy sessionInformationExpiredStrategy = getSessionInformationExpiredStrategy();


        http
                //配置所有的Http请求必须认证
                .authorizeHttpRequests(authorize -> {
                    //子类需要放行的URL
                    if (ArrayUtils.isNotEmpty(permitAllUrls)) {
                        authorize.requestMatchers(permitAllUrls).permitAll();
                    }
                    //需要指定角色访问
                    if (MapUtils.isNotEmpty(hasRoleMap)) {
                        for (Map.Entry<String, String> entry : hasRoleMap.entrySet()) {
                            if (StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())) {
                                authorize.requestMatchers(entry.getKey()).hasRole(entry.getValue());
                            }
                        }
                    }
                    //需要指定权限访问
                    if (MapUtils.isNotEmpty(hasAuthorityMap)) {
                        for (Map.Entry<String, String> entry : hasAuthorityMap.entrySet()) {
                            if (StringUtils.isNotBlank(entry.getKey()) && StringUtils.isNotBlank(entry.getValue())) {
                                authorize.requestMatchers(entry.getKey()).hasAuthority(entry.getValue());
                            }
                        }
                    }
                    authorize
                            .requestMatchers(defaultPermitAllUrls).permitAll()
                            .anyRequest().authenticated();
                })
                //异常配置
                .exceptionHandling(exception -> {
                    if (authenticationEntryPoint != null){
                        exception.authenticationEntryPoint(authenticationEntryPoint);
                    }
                    if (accessDeniedHandler != null){
                        exception.accessDeniedHandler(accessDeniedHandler);
                    }
                })
                //注销
                .logout(logout -> {
                            logout
                                    //.logoutUrl(getLogoutProcessingUrl())
                                    .logoutRequestMatcher(new OrRequestMatcher(
                                            PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.GET, getLogoutProcessingUrl()),
                                            PathPatternRequestMatcher.withDefaults().matcher(HttpMethod.POST, getLogoutProcessingUrl())
                                    ))
                                    .deleteCookies(ArrayUtils.addAll(getDefaultDeleteCookies(), getDeleteCookies()))//删除某些指定 cookie, 添加一个CookieClearingLogoutHandler
                                    .clearAuthentication(true) // 清理Authentication ，默认true
                                    .invalidateHttpSession(true); // 设置当前登录用户Session（保存登录后的用户信息）无效，默认true
                            if (logoutHandler != null) {
                                logout.addLogoutHandler(logoutHandler);//自定义注销处理器
                            }
                            //使用官方默认登录页时，不需配置自定义注销成功处理。框架会自动处理。
                            if (!useDefaultLoginUrl()){
                                if (logoutSuccessHandler != null) {
                                    logout.logoutSuccessHandler(logoutSuccessHandler);//自定义注销成功处理器
                                } else {
                                    logout.logoutSuccessUrl(getLogoutSuccessUrl());//自定义注销成功跳转地址
                                }
                            }
                        }
                )
                //会话创建策略 默认IF_REQUIRED
                .sessionManagement(session -> {
                            //会话失效（超时）
                            if (invalidSessionStrategy != null) {
                                session.invalidSessionStrategy(invalidSessionStrategy);//session超时 前后端分离
                            } else {
                                session.invalidSessionUrl(getInvalidSessionUrl());
                            }
                            session
                                    .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)//创建策略
                                    .sessionFixation(SessionManagementConfigurer.SessionFixationConfigurer::changeSessionId);//会话固定攻击保护策略 默认 changeSessionId
                            //控制session的并发
                            if ((getMaxSessions() != null && getMaxSessions() > 0) || yumengAuthProperties.getJwt().getSingleLogin()){
                                int maxSessions = yumengAuthProperties.getJwt().getSingleLogin() ? 1 : getMaxSessions();
                                SessionManagementConfigurer<HttpSecurity>.ConcurrencyControlConfigurer concurrency
                                        = session.maximumSessions(maxSessions);
                                //如果阻止超过阈值登录，当已存在会话没有正常注销的话，会存在其他会话登录异常的情况
                                concurrency.maxSessionsPreventsLogin(maxSessionsPreventsLogin());
                                //会话到期（在线踢人）
                                if (sessionInformationExpiredStrategy != null) {
                                    concurrency.expiredSessionStrategy(sessionInformationExpiredStrategy);
                                } else {
                                    concurrency.expiredUrl(getExpiredSessionUrl());
                                }
                            }
                        }
                )
                //自定义时需关闭，否则会有异常（要支持csrf可能需要额外配置）AbstractHttpConfigurer::disable Customizer.withDefaults()
                .csrf((csrf) -> {
                            if (CsrfModel.COOKIE_REP.equals(getCsrfModel())) {
                                CookieCsrfTokenRepository repository = CookieCsrfTokenRepository.withHttpOnlyFalse();
                                repository.setCookieName(getCsrfCookieName());
                                csrf
                                        .csrfTokenRepository(repository)
                                        //XorCsrfTokenRequestAttributeHandler csrf令牌会变化
                                        .csrfTokenRequestHandler(new CsrfTokenRequestAttributeHandler());
                            } else if (CsrfModel.SESSION_REP.equals(getCsrfModel())) {
                                csrf.csrfTokenRepository(new HttpSessionCsrfTokenRepository());
                            } else {
                                csrf.disable();
                            }
                        }
                )
                .rememberMe(rm -> {
                            if (RememberMeModel.COOKIE_REP.equals(getRememberMeModel())) {
                                rm
                                        .key(getRememberMeKey())
                                        .alwaysRemember(getAlwaysRememberMe())//始终开启记住我
                                        .useSecureCookie(getRememberMeSecureCookie())//是否只支持https
                                        .rememberMeParameter(getRememberMeParameter())//传递的参数
                                        .rememberMeCookieName(getRememberMeCookieName())//配置自定义cookie名
                                        .tokenValiditySeconds(getRememberMeValiditySeconds());//记住我有效时间

                                if (getRememberMeCookieDomain() != null) {
                                    rm.rememberMeCookieDomain(getRememberMeCookieDomain());//可以访问该cookie的域名
                                }

                            } else if (RememberMeModel.PERSISTENT_REP.equals(getRememberMeModel())) {
                                rm.rememberMeServices(persistentRememberMeServices());
                            } else {
                                rm.disable();
                            }

                        }
                );
        //是否启用自定义登录（普通）
        if (enableNormalAuth()){
            http.with(normalLogin(), getNormalLoginConfigurerCustomizer(authenticationSuccessHandler, authenticationFailureHandler));
        }else{
            http.formLogin(getFormLoginConfigurerCustomizer(authenticationSuccessHandler, authenticationFailureHandler));
        }
        //是否启用自定义登录（短信验证码）
        if (enableSmsAuth()){
            http.with(smsLogin(smsAuthService), getSmsLoginConfigurerCustomizer(authenticationSuccessHandler, authenticationFailureHandler));
        }

        if (!enableRequestCache()){
            http.requestCache(RequestCacheConfigurer::disable);
        }
        if (!enableAnonymous()){
            http.anonymous(AbstractHttpConfigurer::disable);
        }
        if (enableOAuth2()){
            http.oauth2Login(oAuth2Login -> oAuth2Login.defaultSuccessUrl(getLoginSuccessUrl()));
        }

        if (enableCaptcha() && CollectionUtils.isNotEmpty(yumengAuthProperties.getBasic().getCaptchaVerifyUrls())){
            http.with(captchaVerify(), captcha->{
                captcha.captchaVerifyUrls(yumengAuthProperties.getBasic().getCaptchaVerifyUrls())
                        .captchaIdParameter(yumengAuthProperties.getBasic().getCaptchaIdParameter())
                        .captchaParameter(yumengAuthProperties.getBasic().getCaptchaParameter());
                        //.failureHandler(createCommonAuthenticationFailureHandler(authenticationFailureHandler));
            });
        }
        return http.build();
    }

    /**
     * 注入自定义UserDetailsServiceBean
     * 默认的InMemoryUserDetailsManager
     * SysUserServiceImpl sysUserService
     */
    @Bean
    public NormalUserDetailsServiceImpl normalUserDetailsServiceImpl() {
        log.info("注入【UserDetailsService】:NormalUserDetailsServiceImpl");
        return new NormalUserDetailsServiceImpl(normalAuthService);
    }


    /**
     * 监听会话生命周期事件
     * <p>
     * 当session变化时，通知spring知道。
     * 否则会出现：当限制会话并发数时，在a处已注销，但是b处还是无法登录
     */
    @Bean
    public HttpSessionEventPublisher httpSessionEventPublisher() {
        return new HttpSessionEventPublisher();
    }

    /**
     * 持久化存储
     */
    private RememberMeServices persistentRememberMeServices() {
        PersistentTokenRepository tokenRepository = getPersistentTokenRepository();
        if (tokenRepository == null) {
            throw new YumengException("未实现持久化存储方案：getPersistentTokenRepository()");
        }
        UserDetailsService userDetailsService = normalUserDetailsServiceImpl();
        PersistentTokenBasedRememberMeServices rememberMeServices = new PersistentTokenBasedRememberMeServices(getRememberMeKey(), userDetailsService, tokenRepository);
        rememberMeServices.setAlwaysRemember(getAlwaysRememberMe());
        rememberMeServices.setUseSecureCookie(getRememberMeSecureCookie());
        rememberMeServices.setParameter(getRememberMeParameter());
        rememberMeServices.setCookieName(getRememberMeCookieName());
        rememberMeServices.setTokenValiditySeconds(getRememberMeValiditySeconds());
        if (getRememberMeCookieDomain() != null) {
            rememberMeServices.setCookieDomain(getRememberMeCookieDomain());
        }
        return rememberMeServices;
    }

    private AuthenticationManager authenticationManager() throws Exception {
        return this.authenticationConfiguration.getAuthenticationManager();
    }

    //标准登录（框架自带）
    private Customizer<FormLoginConfigurer<HttpSecurity>> getFormLoginConfigurerCustomizer(AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
        return login -> {
            login
                    .usernameParameter(getLoginUsernameParameter())//自定义用户名参数名称
                    .passwordParameter(getLoginPasswordParameter());//自定义密码参数名称
            if (!useDefaultLoginUrl()) {
                login.loginPage(getLoginUrl());//自定义登录页面（注意同步配置loginProcessingUrl）
            }
            login.loginProcessingUrl(getLoginProcessingUrl());//自定义登录处理URL
            applyCommonLoginConfig(login, authenticationSuccessHandler, authenticationFailureHandler);
        };
    }
    //自定义普通登录
    private Customizer<NormalLoginConfigurer<HttpSecurity>> getNormalLoginConfigurerCustomizer(AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
        return login -> {
            login
                    .usernameParameter(getLoginUsernameParameter())//自定义用户名参数名称
                    .passwordParameter(getLoginPasswordParameter());//自定义密码参数名称
            if (!useDefaultLoginUrl()) {
                login.loginPage(getLoginUrl());//自定义登录页面（注意同步配置loginProcessingUrl）
            }
            login.loginProcessingUrl(getLoginProcessingUrl());//自定义登录处理URL
            applyCustomLoginConfig(login, authenticationSuccessHandler, authenticationFailureHandler);
        };
    }
    //自定义短信验证码登录
    private Customizer<SmsLoginConfigurer<HttpSecurity>> getSmsLoginConfigurerCustomizer(AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler) {
        return login -> {
            login
                    .phoneParameter(getSmsLoginUsernameParameter())//自定义用户名参数名称
                    .smsCodeParameter(getSmsLoginPasswordParameter());//自定义密码参数名称
            if (!useDefaultLoginUrl()) {
                login.loginPage(getSmsLoginUrl());//自定义登录页面（注意同步配置loginProcessingUrl）
            }
            login.loginProcessingUrl(getSmsLoginAction());//自定义登录处理URL
            applyCustomLoginConfig(login, authenticationSuccessHandler, authenticationFailureHandler);
        };
    }


    private void applyCommonLoginConfig(AbstractAuthenticationFilterConfigurer<HttpSecurity, ?, ?> loginConfigurer, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler){
        if (authenticationSuccessHandler != null) {
            loginConfigurer.successHandler(authenticationSuccessHandler);//认证成功处理器
        } else {
            loginConfigurer.defaultSuccessUrl(getLoginSuccessUrl());//自定义登录成功RUL
        }
        if (authenticationFailureHandler != null) {
            loginConfigurer.failureHandler(authenticationFailureHandler);//认证失败处理器
        } else {
            loginConfigurer.failureUrl(getLoginFailureUrl());//自定义登录失败RUL
        }
    }
    private void applyCustomLoginConfig(MyAbstractAuthenticationFilterConfigurer<HttpSecurity, ?, ?> loginConfigurer, AuthenticationSuccessHandler authenticationSuccessHandler, AuthenticationFailureHandler authenticationFailureHandler){
        loginConfigurer
                .clientTypeParameter(getClientTypeParameter())
                .jsonParam(false)
                .postOnly(true)
                .authenticationDetailsSource(new CustomWebAuthenticationDetailsSource());
        if (authenticationSuccessHandler != null) {
            loginConfigurer.successHandler(authenticationSuccessHandler);//认证成功处理器
        } else {
            loginConfigurer.defaultSuccessUrl(getLoginSuccessUrl());//自定义登录成功RUL
        }
        if (authenticationFailureHandler != null) {
            loginConfigurer.failureHandler(authenticationFailureHandler);//认证失败处理器
        } else {
            loginConfigurer.failureUrl(getLoginFailureUrl());//自定义登录失败RUL
        }
    }

    /**
     * 根据配置的 LoginFailureUrl 和 AuthenticationFailureHandler，综合生成AuthenticationFailureHandler
     *
     * @param defaultFailureHandler
     * @return
     */
    private AuthenticationFailureHandler createCommonAuthenticationFailureHandler(AuthenticationFailureHandler defaultFailureHandler) {
        if (defaultFailureHandler != null){
            return defaultFailureHandler;
        }
        return new SimpleUrlAuthenticationFailureHandler(getLoginFailureUrl());
    }


    /**
     * CSRF模式
     */
    protected enum CsrfModel {
        /**
         * 禁用CSRF
         */
        DISABLE,
        /**
         * 基于Cookie的存储
         */
        COOKIE_REP,
        /**
         * 基于Session的存储
         */
        SESSION_REP
    }

    /**
     * 记住我模式
     */
    protected enum RememberMeModel {
        /**
         * 禁用记住我
         */
        DISABLE,
        /**
         * 基于Cookie的存储
         */
        COOKIE_REP,
        /**
         * 基于持久化的存储
         */
        PERSISTENT_REP
    }


//==================================================================================================================================备用

    /**
     * 静态资源放行
     * 不建议使用该方法
     * 后期如果不支持ignoring()方法的话，可直接注释掉。唯一存在的问题是：当没有独立的前端页面时，且会话失效时，无法打开LogoutUrl
     * @return
     */
/*    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return web->{
            List<String> patterns = new ArrayList<>();
            patterns.add(webMvcProperties.getStaticPathPattern());
            patterns.add(yumengProperties.getSecurity().getLogoutUrl());
            String[] patternsArray = patterns.toArray(new String[0]);
            web.ignoring().requestMatchers(patternsArray);
        };
    }*/


//==================================================================================================================================备忘
    // 以/db/开头的请求，必须同时拥有ADMIN、DBA角色
    //.requestMatchers("/perm2/**").access(new WebExpressionAuthorizationManager("hasRole('admin') and hasRole('dba')"))
    //.requestMatchers("/db/**").access(AuthorizationManagers.allOf(AuthorityAuthorizationManager.hasRole("ADMIN"), AuthorityAuthorizationManager.hasRole("DBA")))
    // /test/开头的所有POST请求的用户，必须具有ADMIN或者USER角色
    //.requestMatchers(new AntPathRequestMatcher("/test/**","POST")).hasAnyRole("ADMIN","USER")

    //=====================================================================================================
    //.httpBasic(Customizer.withDefaults())
    //.passwordManagement(Customizer.withDefaults())
    //.rememberMe(Customizer.withDefaults())
    //.addFilterAfter(new TestFilter(), AuthorizationFilter.class);

}
